package com.okex.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.okex.demo.model.Account;
import com.okex.demo.model.OrderInfo;
import com.okex.demo.model.PositionInfo;
import com.okex.demo.model.TickerInfo;
import com.okex.demo.service.AccountService;
import com.okex.demo.service.DataPollingService;
import com.okex.demo.service.OkexApiService;
import com.okex.demo.service.OrderService;
import com.okex.demo.service.PositionPollingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.HashMap;

/**
 * REST API 控制器
 * 提供直接HTTP访问数据的接口，作为WebSocket的备用方案
 */
@Slf4j
@RestController
@RequestMapping("/api/v2")
public class ApiController {

    @Autowired
    private OkexApiService okexApiService;

    @Autowired
    private PositionPollingService positionPollingService;

    @Autowired
    private DataPollingService dataPollingService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private AccountService accountService;

    /**
     * 获取单个产品行情
     */
    @GetMapping("/ticker")
    public ResponseEntity<TickerInfo> getTicker(@RequestParam(required = false) String instId) {
        log.info("HTTP API请求产品行情: {}", instId);
        try {
            TickerInfo ticker = okexApiService.getTicker(instId);
            if (ticker != null) {
                // 强制更新时间戳为当前时间，确保前端显示最新更新时间
                Date currentTime = new Date();
                ticker.setUpdateTime(currentTime);
                log.info("HTTP API返回产品行情，更新时间戳: {}, instId: {}", currentTime, instId);

                // 添加到订阅列表
                dataPollingService.addSubscription(instId);

                return ResponseEntity.ok(ticker);
            } else {
                log.warn("未找到产品行情: {}", instId);
                return ResponseEntity.noContent().build();
            }
        } catch (Exception e) {
            log.error("获取产品行情出错: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 获取产品行情列表
     * 支持两种模式：
     * 1. 指定instIds参数：只获取指定产品的行情（推荐）
     * 2. 不指定instIds参数：获取instType类型下的所有产品行情（不推荐，可能较慢且耗资源）
     */
    @GetMapping("/tickers")
    public ResponseEntity<List<TickerInfo>> getTickers(
            @RequestParam String instType,
            @RequestParam(required = false) List<String> instIds,
            @RequestParam(required = false) String uly,
            @RequestParam(required = false) String instFamily) {

        log.info("HTTP API请求行情列表: instType={}, instIds数量={}, uly={}, instFamily={}",
                instType, instIds != null ? instIds.size() : 0, uly, instFamily);

        try {
            // 如果提供了产品ID列表，则只查询这些产品
            if (instIds != null && !instIds.isEmpty()) {
                List<TickerInfo> tickers = new ArrayList<>();
                Date now = new Date();

                for (String instId : instIds) {
                    if (instId != null && !instId.trim().isEmpty()) {
                        log.debug("查询产品行情: {}", instId);
                        TickerInfo ticker = okexApiService.getTicker(instId);

                        if (ticker != null) {
                            // 设置产品类型和更新时间
                            if (ticker.getInstType() == null || ticker.getInstType().isEmpty()) {
                                ticker.setInstType(instType);
                            }
                            ticker.setUpdateTime(now);
                            tickers.add(ticker);

                            // 将产品添加到订阅列表
                            dataPollingService.addSubscription(instId);
                        } else {
                            log.warn("产品 {} 行情查询失败", instId);
                        }
                    }
                }

                log.info("返回 {} 条产品行情数据", tickers.size());
                return ResponseEntity.ok(tickers);
            }
            // 如果没有提供产品ID列表，则查询整个类型（不推荐）
            else {
                log.warn("未指定产品列表，将查询整个类型的所有产品(不推荐)：{}", instType);
                List<TickerInfo> tickers = okexApiService.getTickersList(instType, uly, instFamily);
                return ResponseEntity.ok(tickers);
            }
        } catch (Exception e) {
            log.error("获取行情列表出错: {}", e.getMessage(), e);
            return ResponseEntity.ok(Collections.emptyList()); // 返回空列表而不是错误
        }
    }

    /**
     * 获取持仓列表
     * 触发一次持仓数据轮询并返回结果
     */
    @GetMapping("/positions")
    public ResponseEntity<List<PositionInfo>> getPositions() {
        log.info("HTTP API请求持仓信息");
        try {
            // 确保数据轮询服务已启动
            if (!positionPollingService.isRunning()) {
                positionPollingService.startPolling();
            }

            // 触发一次数据轮询
            positionPollingService.triggerPoll();

            // 获取持仓数据
            List<PositionInfo> positions = okexApiService.getPositions();
            log.info("获取到 {} 条持仓信息", positions.size());

            // 确保每个持仓都有更新时间和有效的instId
            Date now = new Date();
            for (PositionInfo position : positions) {
                position.setUpdateTime(now);
            }

            return ResponseEntity.ok(positions);
        } catch (Exception e) {
            log.error("获取持仓列表出错: {}", e.getMessage(), e);
            return ResponseEntity.ok(Collections.emptyList()); // 返回空列表而不是错误
        }
    }

    /**
     * 平仓操作
     * 执行平仓后触发持仓数据刷新
     */
    @PostMapping("/close-positions")
    public ResponseEntity<?> closePosition(
            @RequestParam String instId,
            @RequestParam String posSide,
            @RequestParam String mgnMode) {

        log.info("HTTP API请求平仓: instId={}, posSide={}, mgnMode={}",
                instId, posSide, mgnMode);

        try {
            JSONObject result = okexApiService.closePosition(instId, posSide, mgnMode);

            // 触发持仓数据更新
            if (positionPollingService.isRunning()) {
                positionPollingService.triggerPoll();
            }
            if (result != null && result.getInteger("code") == 0) {
                Optional<Account> flexibleMatching = accountService.findByInstIdWithFlexibleMatching(instId);
                Account account = flexibleMatching.get();
               //posid=long cross
                if ("longcross".equals(posSide+mgnMode)){
                    account.setCrossLongReplenishCount(1);
                    account.setCrossLongCost(BigDecimal.ZERO);
                }else if ("shortcross".equals(posSide+mgnMode)){
                    account.setCrossShortReplenishCount(1);
                    account.setCrossShortCost(BigDecimal.ZERO);

                }
                accountService.saveWithFieldPreservation(account);
            }

            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("平仓操作出错: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 下单操作
     * 执行下单并保存订单记录
     */
    @PostMapping("/place-order")
    public ResponseEntity<?> placeOrder(
            @RequestParam String instId,
            @RequestParam String tdMode,
            @RequestParam String side,
            @RequestParam String posSide,
            @RequestParam String sz,
            @RequestParam(required = false) String leverage,
            @RequestParam(required = false) BigDecimal amount) {

        log.info("HTTP API请求下单: instId={}, tdMode={}, side={}, posSide={}, sz={}, leverage={}, amount={}",
                instId, tdMode, side, posSide, sz, leverage, amount);

        try {
            // 如果提供了amount，则使用后端计算订单大小
            String finalSz = sz;
            if (amount != null && amount.compareTo(BigDecimal.ZERO) > 0) {
                // 获取最新行情
                TickerInfo ticker = okexApiService.getTicker(instId);
                if (ticker != null && ticker.getLast() != null) {
                    BigDecimal price = ticker.getLast();
                    log.info("使用最新价格计算订单大小: 产品={}, 价格={}", instId, price);

                    // 获取产品面值
                    final BigDecimal[] faceValue = {BigDecimal.valueOf(0.01)}; // 默认值

                    // 尝试从账户配置中获取面值
                    accountService.findByInstId(instId).ifPresent(account -> {
                        if (account.getFaceValue() != null) {
                            faceValue[0] = account.getFaceValue();
                        }
                    });

                    // 计算杠杆倍数
                    BigDecimal leverNum = BigDecimal.valueOf(20); // 默认杠杆
                    if (leverage != null && !leverage.isEmpty()) {
                        try {
                            leverNum = new BigDecimal(leverage);
                        } catch (NumberFormatException e) {
                            log.warn("杠杆倍数格式错误，使用默认值: {}", leverage);
                        }
                    }

                    // 计算合约面值（单位：USD）
                    BigDecimal contractValue = price.multiply(faceValue[0]);

                    // 张数 = 保证金*杠杆倍数 / (面值*价格)
                    BigDecimal calculatedSize = amount.multiply(leverNum).divide(contractValue, 2, BigDecimal.ROUND_DOWN);

                    // 确保至少有1张，并取整
                    if (calculatedSize.compareTo(BigDecimal.ONE) < 0) {
                        calculatedSize = BigDecimal.ONE;
                    }

                    finalSz = calculatedSize.doubleValue() + "";
                    log.info("后端计算订单大小: 金额={}, 杠杆={}, 价格={}, 面值={}, 计算结果={}, 前端值={}",
                            amount, leverNum, price, faceValue[0], finalSz, sz);
                } else {
                    log.warn("无法获取最新价格，使用前端计算的订单大小: {}", sz);
                }
            } else {
                log.info("使用前端计算的订单大小: {}", sz);
            }

            // 执行下单
            JSONObject result = okexApiService.placeOrder(instId, tdMode, side, posSide, finalSz, leverage);

            // 保存订单记录
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setInstId(instId);
            orderInfo.setTdMode(tdMode);
            orderInfo.setSide(side);
            orderInfo.setPosSide(posSide);
            orderInfo.setSz(new BigDecimal(finalSz));
            orderInfo.setAmount(amount);
            orderInfo.setCreateTime(new Date());

            // 设置杠杆倍数
            if (leverage != null && !leverage.isEmpty()) {
                try {
                    orderInfo.setLeverage(new BigDecimal(leverage));
                } catch (NumberFormatException e) {
                    log.warn("杠杆倍数格式错误: {}", leverage);
                }
            }

            // 设置返回结果
            if (result != null) {
                orderInfo.setCode(result.getInteger("code"));
                orderInfo.setMsg(result.getString("msg"));

                // 如果成功，设置订单ID
                if (result.getInteger("code") == 0 && result.getJSONArray("data") != null
                        && !result.getJSONArray("data").isEmpty()) {
                    JSONObject data = result.getJSONArray("data").getJSONObject(0);
                    orderInfo.setOrdId(data.getString("ordId"));
                    orderInfo.setClOrdId(data.getString("clOrdId"));
                }
            } else {
                orderInfo.setCode(-1);
                orderInfo.setMsg("API返回结果为空");
            }

            // 保存订单记录
            orderService.saveOrder(orderInfo);

            // 触发持仓数据更新
            if (positionPollingService.isRunning()) {
                positionPollingService.triggerPoll();
            }

            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("下单操作出错: {}", e.getMessage(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 获取订单列表
     * 支持按产品ID和时间范围过滤
     */
    @GetMapping("/orders")
    public ResponseEntity<List<OrderInfo>> getOrders(
            @RequestParam(required = false) String instId,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {

        log.info("HTTP API请求订单列表: instId={}, startDate={}, endDate={}",
                instId, startDate, endDate);

        try {
            // 调整结束日期为当天的23:59:59
            if (endDate != null) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(endDate);
                calendar.set(Calendar.HOUR_OF_DAY, 23);
                calendar.set(Calendar.MINUTE, 59);
                calendar.set(Calendar.SECOND, 59);
                calendar.set(Calendar.MILLISECOND, 999);
                endDate = calendar.getTime();
            }

            List<OrderInfo> orders;

            // 根据参数决定查询方式
            if (instId != null && !instId.isEmpty()) {
                if (startDate != null && endDate != null) {
                    // 按产品ID和时间范围查询
                    orders = orderService.findOrdersByInstIdAndDateRange(instId, startDate, endDate);
                } else {
                    // 仅按产品ID查询
                    orders = orderService.findOrdersByInstId(instId);
                }
            } else {
                if (startDate != null && endDate != null) {
                    // 仅按时间范围查询
                    orders = orderService.findOrdersByDateRange(startDate, endDate);
                } else {
                    // 查询当天订单
                    orders = orderService.findTodayOrders();
                }
            }

            log.info("获取到 {} 条订单记录", orders.size());
            return ResponseEntity.ok(orders);
        } catch (Exception e) {
            log.error("获取订单列表出错: {}", e.getMessage(), e);
            return ResponseEntity.ok(Collections.emptyList()); // 返回空列表而不是错误
        }
    }

    /**
     * 删除订单记录
     * 支持按产品ID和时间范围删除
     */
    @DeleteMapping("/orders")
    public ResponseEntity<?> deleteOrders(
            @RequestParam(required = false) String instId,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {

        log.info("HTTP API请求删除订单: instId={}, startDate={}, endDate={}",
                instId, startDate, endDate);

        try {
            // 参数校验
            if (startDate == null || endDate == null) {
                return ResponseEntity.badRequest().body("开始日期和结束日期不能为空");
            }

            // 调整结束日期为当天的23:59:59
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(endDate);
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MILLISECOND, 999);
            endDate = calendar.getTime();

            int deletedCount;

            // 根据参数决定删除方式
            if (instId != null && !instId.isEmpty()) {
                // 删除指定产品ID和时间范围内的订单
                deletedCount = orderService.deleteOrdersByInstIdAndDateRange(instId, startDate, endDate);
            } else {
                // 删除时间范围内的所有订单
                deletedCount = orderService.deleteOrdersByDateRange(startDate, endDate);
            }

            log.info("成功删除 {} 条订单记录", deletedCount);

            JSONObject result = new JSONObject();
            result.put("code", 0);
            result.put("msg", "成功删除 " + deletedCount + " 条订单记录");
            result.put("count", deletedCount);

            return ResponseEntity.ok(result);
        } catch (Exception e) {
            log.error("删除订单记录出错: {}", e.getMessage(), e);

            JSONObject result = new JSONObject();
            result.put("code", -1);
            result.put("msg", "删除订单记录失败: " + e.getMessage());

            return ResponseEntity.ok(result);
        }
    }

    /**
     * 计算订单大小API
     * 根据保证金金额、杠杆倍数、当前价格和产品ID计算可下单的数量
     */
    @GetMapping("/calculate-order-size")
    public ResponseEntity<?> calculateOrderSize(
            @RequestParam String instId,
            @RequestParam BigDecimal amount,
            @RequestParam String leverage,
            @RequestParam(required = false) BigDecimal price) {

        log.info("请求计算订单大小: instId={}, amount={}, leverage={}, price={}",
                instId, amount, leverage, price);

        try {
            // 如果没有提供价格，获取最新行情价格
            if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
                TickerInfo ticker = okexApiService.getTicker(instId);
                if (ticker != null && ticker.getLast() != null) {
                    price = ticker.getLast();
                    log.info("使用最新价格: {}", price);
                } else {
                    return ResponseEntity.badRequest().body("无法获取产品价格，请手动输入");
                }
            }

            // 获取产品面值
            final BigDecimal[] faceValue = {BigDecimal.valueOf(0.01)}; // 默认值

            // 尝试从账户配置中获取面值
            accountService.findByInstId(instId).ifPresent(account -> {
                if (account.getFaceValue() != null) {
                    faceValue[0] = account.getFaceValue();
                }
            });

            // 计算合约面值（单位：USD）
            BigDecimal contractValue = price.multiply(faceValue[0]);

            // 确保面值不为0，避免除以0的错误
            if (contractValue.compareTo(BigDecimal.ZERO) <= 0) {
                log.error("计算订单数量失败: 合约面值为0或负数");
                return ResponseEntity.badRequest().body("计算失败：合约面值无效");
            }

            // 计算可买入的合约数量
            BigDecimal leverNum = new BigDecimal(leverage);

            // 张数 = 保证金*杠杆倍数 / (面值*价格)
            BigDecimal size = amount.multiply(leverNum).divide(contractValue, 8, BigDecimal.ROUND_DOWN);

            // 取整，确保是整数，符合交易所lot size要求
            size = new BigDecimal(size.intValue());

            // 确保至少为1张
            if (size.compareTo(BigDecimal.ONE) < 0) {
                size = BigDecimal.ONE;
            }

            // 返回计算结果
            JSONObject result = new JSONObject();
            result.put("code", 0);
            result.put("size", size.stripTrailingZeros().toPlainString());
            result.put("price", price);
            result.put("faceValue", faceValue[0]);

            log.info("计算结果: size={}, price={}, faceValue={}",
                    size, price, faceValue[0]);

            return ResponseEntity.ok(result);

        } catch (Exception e) {
            log.error("计算订单大小出错: {}", e.getMessage(), e);

            JSONObject result = new JSONObject();
            result.put("code", -1);
            result.put("msg", "计算失败: " + e.getMessage());

            return ResponseEntity.ok(result);
        }
    }

    /**
     * 获取账户配置
     * 根据产品ID获取对应的账户配置信息
     */
    @GetMapping("/account")
    public ResponseEntity<?> getAccount(@RequestParam String instId) {
        log.info("请求获取账户配置: instId={}", instId);

        try {
            // 查找账户配置
            return accountService.findByInstId(instId)
                    .map(account -> {
                        // 返回账户配置
                        JSONObject result = new JSONObject();
                        result.put("instId", account.getInstId());
                        result.put("accountName", account.getAccountName());
                        result.put("faceValue", account.getFaceValue());
                        result.put("leverage", account.getLeverage());

                        log.info("获取账户配置成功: instId={}, faceValue={}",
                                instId, account.getFaceValue());

                        return ResponseEntity.ok(result);
                    })
                    .orElseGet(() -> {
                        // 账户配置不存在
                        log.warn("账户配置不存在: instId={}", instId);

                        JSONObject result = new JSONObject();
                        result.put("instId", instId);
                        result.put("faceValue", 0.01); // 默认面值

                        return ResponseEntity.ok(result);
                    });
        } catch (Exception e) {
            log.error("获取账户配置出错: {}", e.getMessage(), e);

            JSONObject result = new JSONObject();
            result.put("instId", instId);
            result.put("faceValue", 0.01); // 默认面值
            result.put("error", e.getMessage());

            return ResponseEntity.ok(result);
        }
    }

    /**
     * 获取账户状态信息
     */
    @GetMapping("/account-status")
    @ResponseBody
    public Map<String, Object> getAccountStatus(@RequestParam String instId) {
        log.info("获取产品状态信息: {}", instId);
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 根据instId查找账户
            Optional<Account> accountOpt = accountService.findByInstId(instId);
            
            if (accountOpt.isPresent()) {
                Account account = accountOpt.get();
                // 提取状态信息
                Map<String, Object> crossInfo = new HashMap<>();
                crossInfo.put("crossLongReplenishCount", account.getCrossLongReplenishCount());
                crossInfo.put("crossShortReplenishCount", account.getCrossShortReplenishCount());
                crossInfo.put("crossLongCost", account.getCrossLongCost());
                crossInfo.put("crossShortCost", account.getCrossShortCost());
                crossInfo.put("crossToIsolatedLongCost", account.getCrossToIsolatedLongCost());
                crossInfo.put("crossToIsolatedShortPriceDiff", account.getCrossToIsolatedShortPriceDiff());
                
                Map<String, Object> isolatedInfo = new HashMap<>();
                isolatedInfo.put("isolatedLongReplenishCount", account.getIsolatedLongReplenishCount());
                isolatedInfo.put("isolatedShortReplenishCount", account.getIsolatedShortReplenishCount());
                isolatedInfo.put("isolatedLongCost", account.getIsolatedLongCost());
                isolatedInfo.put("isolatedShortCost", account.getIsolatedShortCost());
                isolatedInfo.put("isTransferIsolatedLong", account.getIsTransferIsolatedLong());
                isolatedInfo.put("isTransferIsolatedShort", account.getIsTransferIsolatedShort());
                
                result.put("code", 0);
                result.put("msg", "success");
                
                Map<String, Object> dataMap = new HashMap<>();
                dataMap.put("crossInfo", crossInfo);
                dataMap.put("isolatedInfo", isolatedInfo);
                dataMap.put("createdAt", account.getCreatedAt());
                dataMap.put("updatedAt", account.getUpdatedAt());
                result.put("data", dataMap);
            } else {
                result.put("code", 1);
                result.put("msg", "未找到产品: " + instId);
            }
        } catch (Exception e) {
            log.error("获取产品状态信息异常", e);
            result.put("code", 1);
            result.put("msg", "获取产品状态失败: " + e.getMessage());
        }
        
        return result;
    }
}
